package com.dh.convert.rule.function;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorNil;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorRuntimeJavaType;

public class ExtSeqFilterFunction extends AbstractFunction {

	@Override
	  @SuppressWarnings("unchecked")
	  public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
	    Object first = arg1.getValue(env);
	    if (first == null) {
	      return AviatorNil.NIL;
	    }
	    String expression = FunctionUtils.getStringValue(arg2, env);
	    if(StringUtils.isBlank(expression)){
	    	throw new NullPointerException("expression is null");
	    }
	    Class<?> clazz = first.getClass();

	    if (Collection.class.isAssignableFrom(clazz)) {
	      Collection<Object> result = null;
	      try {
	        result = (Collection<Object>) clazz.newInstance();
	      } catch (Throwable t) {
	        // ignore
	        result = new ArrayList<Object>();
	      }
	      for (Object obj : (Collection<?>) first) {
	    	env.put("ENTRY", obj);
	        if ((boolean) AviatorEvaluator.execute(expression, env, Boolean.TRUE)) {
	          result.add(obj);
	        }
	      }
	      return new AviatorRuntimeJavaType(result);
	    } else if (Map.class.isAssignableFrom(clazz)) {
	      Map<Object, Object> result;
	      try {
	        result = (Map<Object, Object>) clazz.newInstance();
	      } catch (Throwable t) {
	        // ignore
	        result = new HashMap<Object, Object>();
	      }
	      Map<?, ?> map = (Map<?, ?>) first;
	      for (Map.Entry<?, ?> entry : map.entrySet()) {
	    	  env.put("ENTRY", entry);
		      if ((boolean) AviatorEvaluator.execute(expression, env, Boolean.TRUE)){
	          result.put(entry.getKey(), entry.getValue());
	        }
	      }
	      return new AviatorRuntimeJavaType(result);
	    } else if (clazz.isArray()) {
	      // Object[] seq = (Object[]) first;
	      List<Object> result = new ArrayList<Object>();
	      int length = Array.getLength(first);
	      for (int i = 0; i < length; i++) {
	        Object obj = Array.get(first, i);
	        env.put("ENTRY", obj);
		    if ((boolean) AviatorEvaluator.execute(expression, env, Boolean.TRUE)){
	          result.add(obj);
	        }
	      }
	      return new AviatorRuntimeJavaType(result.toArray());
	    } else {
	      throw new IllegalArgumentException(arg1.desc(env) + " is not a seq collection");
	    }

	  }


	  @Override
	  public String getName() {
	    return "extFilter";
	  }
}
